/*******************************************************************************

    copyright:      Copyright (c) 2007 Matthias Walter. All rights reserved

    license:    BSD style: $(LICENSE)

    version:    Initial release: May 2007

    author:     Matthias Walter

*******************************************************************************/

module fcgi.Application;

private import  fcgi.Request;
private import  fcgi.Connection;
private import  fcgi.Exception;

private import  tango.core.Thread;

abstract class FastCGIApplication
{
    private static FastCGIApplication[] all_;

    private FastCGIRequest request_;
    private Thread thread_;
    private bool active_;
    private int threadID_;

    public int id ()
    {
        return threadID_;
    }

    public bool[] getActive ()
    {
      bool[] active = new bool[all_.length];
      foreach (i, thread; all_)
        active[i] = thread.active_;
      return active;
    }

    private void start ()
    {
        thread_.start ();
    }

    private void join ()
    {
        thread_.join ();
    }

    public FastCGIRequest request ()
    {
        return request_;
    }

    protected abstract int run ();

    private final void run_ ()
    {
        while (true)
        {
            try
            {
                if (!request_.accept ())
                    break;
                request_.exitStatus = run ();
                request_.finish ();
            }
            catch (FastCGIProtocolException e)
            {
                // Fatal errors are forwarded
                throw e;
            }
            catch (FastCGIAbortException e)
            {
                // AbortRequest errors only inform the handler-loop
            }
            catch (Exception e)
            {
                // All user-exceptions are printed to stderr
                if (request_.isFinished ())
                    throw e;
                else
                {
                    request_.exitStatus = 1;
                    request_.stderr.write (e.msg);
                    request_.finish ();
                }
            }
        }
    }

    public static int loop(T) (FastCGIConnection connection, bool withExceptions = true, int initialThreads = 1)
    {
        synchronized
        {
            if (initialThreads < 1)
                return 0;
 
            if (connection is null)
                connection = new FastCGIConnection ();

            if (connection.isCGI && initialThreads > 1)
                initialThreads = 1;

            all_ = new T[initialThreads];
            foreach (i, t; all_)
            {
                FastCGIRequest request = new FastCGIRequest (connection, withExceptions);
                all_[i] = new T (i, request);
                all_[i].request_ = request;
                all_[i].thread_ = new Thread (&(all_[i].run_));
                all_[i].active_ = false;
                all_[i].threadID_ = i;
            }

            foreach (t; all_)
            {
                t.start ();
            }

            foreach (t; all_)
            {
                t.join ();
            }

            if (connection.isCGI)
                return all_[0].request_.exitStatus;
        }
    }
};
